;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
;程序名称:clock.asm
;功能:常驻计时器/闹钟/大时钟
;环境:16BIT DOS实模式
;编译器:MASM 5.1-6X
;用法:看说明
;返回值:没有
;破坏寄存器:不适用
;
;
;这是吧上某人的功课吧
;这题目有普遍性，涉及的问题较多，所以独立发一帖，希望多些人看到．
;
;参照 “定时响铃”的例子及其它MASM程序的例子,实现 INT 1C
;MYINT1C 实现的功能在屏幕的右上角显示秒表或时钟，按ESC，
;退出程序。
;说明：
;1.实现基本的秒表功能，即参照8.5范例给出的响铃程序改写，
;实现简单的计时和暂停、中止等功能；
;2.时钟复杂一些，按照书后BIOS/DOS中断附表实现从系
;统取时间，并能够对其进行设置和相应的计时功能。
;
;解题
;DOS的常驻，时钟比较简单，基本上拦截1CH，抓取系统时间，
;找个地方显示一下就完事了，至于计时，方法也有许多，1CH
;本身就是每1/18.2秒运行一次，所以同时也有计时功能．
;常驻的方法用DOS的21H,AH=31H或者INT27也可以．
;这个小小CLOCK程式的计时和读时间不用任何中断int21h,ah=2ch
;或int 1Ah,而是直接读取40:6C - 40:6D的系统累加时间，这相容度好象
;还大，测试在windows/dos 和dosbox都能正常运行
;编译：因为程式是com，masm 5.x 须要exe2bin  转成com>　exe2bin clock.exe clock.com
;masm 6.x的话加　ml /AT　的设定可直接转成com
;
;用法：
;clock   ;在右上角显示时间
;clock u  ; 移除常驻
;clock c  ;大时钟
;clock s mm:ss
;mm是分钟，ss是秒
;键入clock s 3:10  　
;右上角显示倒数计时3:10 ..3:09...3:08 直到00:00时显示3秒红色 -alarm-文字
;然后回到正常系统时间
;若键入　clock s 10，程式会视为倒数10分钟，若只要倒数秒
;可键入　clock s 0:10 ;则数10秒
;若clock已经常驻，也可以键入clock s mm:ss 去设定新的倒数
;
;补充:
;增加大时钟功能:-
;吧友问题,希望能够在DOS窗口中以像素点形式对绘制一个数字时钟或表盘时钟；
;有基本的控制操作，例如：修改时间、控制时钟显示位置等（自行发挥）。
;（较易，但 “分”低）也可绘制最基本的阿拉伯数字时钟，
;但必须配合键盘或其他对时钟的一些功能控制！
;
;解:
;像素点形式就免了,没这个时间,但其他功能倒可以实现
;代码取用楼上的小时钟，保留所有功能，只增加了大时钟
;使用方法：
;clock c
;
;注意:这只是一个范例程式，具备最起码的功能，没有太花巧的技术
;若你需要其他功能或加入或删减任何代码，请随便，但不能要求作者为你订制特定的功能或
;根据功课要求而改变这个子程序改变那个子程序，若是代码错误或优化代码的意见，
;则欢迎提出:)
;
;代码有简单的中/英文注解,要交功课的同学请自行添加／翻译注解,不要问我!
;交功课的最好不要全抄，应吸收理解后做适当的修改，因为这是本人已公开的代码，
;任何人都可以取用，因抄袭而挂科责任自付！
;
.286

REMOVE_AX       EQU     0AA01H ;移除标志
ASK_AX          EQU     0AA02H ;询问是否已驻留
Alarm_set_ask   equ     0AA03H ;设定闹钟标志
EXIST_FLAG      EQU     0AAFFH ;已驻留标志
time_att        EQU     70H ;时钟颜色
alarm_att       EQU     0cfH ;闹钟颜色
alarm_time      equ     18*3    ; ?  alarm seconds 闹钟时间 3秒
clock_x         equ     17
clock_y         equ     10
clock_color     equ     1Eh
back_color      equ     3fh
esc_key         equ     01h
up_key          equ     48h
down_key        equ     50h
left_key        equ     4bh
right_key       equ     4dh
clock_menu_color equ    1Fh
clock_menu_x    equ     18
clock_menu_y    equ     17
box_x           equ     10
box_y           equ     4               ;top left
box1_x          equ     70
box1_y          equ     20              ;bottom right
alarm_x         equ     box1_x - 7
alarm_y         equ     box_y
;clock_L         equ     42

                cseg    segment
                assume cs:cseg
                org     100h
begin:          jmp     INIT

OLD_OFF         DW      0 ;旧1c中断offset
OLD_SEG         DW      0 ;旧1c中断segment
delay_count     dw      0 ;延迟计数
work_flag       db      0 ;工作中标志
alarm_flag    db	0		;闹钟标志
alarm_count     dw      alarm_time ;闹钟计数
N_clock         db      0       ;1 = active, 2=run ;大时钟标志,1=启动,2=开动
clock_dit       db      0  ;大时钟显示的计数,轮到那个数字?
old_time	dw	0
clock_init      dd      0
ori_hourmin     dw      0
ori_sec         dw      0
hour            db      0
min             db      0
sec             db      0
dit_limit       db      2,9,3,5,9,9,5,9,9 ;大时钟间隔
settime_flag    db      0  ;设定时间标志
clock_mx        db      clock_x
clock_my        db      clock_y
lost_alarm_off  dw      0
alarm_doing     db      0


Number          db      219,223,223,223,219    ;'HHHHH';以下是大时钟框线ascii码,分别为上下和全块实心方块
                db      219,32,32,32,219       ;'H   H';这些扩充ASCII字元(大于128)无法在window下的编辑器正常显示，
                db      219,32,32,32,219       ;'H   H';这里做了转换，把字元换成ASCII编码，显示的H字，
                db      219,32,32,32,219       ;'H   H';只是让大家看清楚大数字样式，实际输出仍是对应的扩充ASCII字元
                db      219,220,220,220,219    ;'HHHHH'
num_L           equ     ($ - offset number)/5
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'

                db      223,223,223,223,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      220,220,220,220,219    ;'HHHHH'
                db      219,32,32,32,32        ;'H    '
                db      219,220,220,220,220    ;'HHHHH'

                db      223,223,223,223,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      220,220,220,220,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      220,220,220,220,219    ;'HHHHH'

                db      219,32,32,32,219       ;'H   H'
                db      219,32,32,32,219       ;'H   H'
                db      219,220,220,220,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'

                db      219,223,223,223,223    ;'HHHHH'
                db      219,32,32,32,32        ;'H    '
                db      219,220,220,220,220    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      220,220,220,220,219    ;'HHHHH'

                db      219,223,223,223,223    ;'HHHHH'
                db      219,32,32,32,32        ;'H    '
                db      219,220,220,220,220    ;'HHHHH'
                db      219,32,32,32,219       ;'H   H'
                db      219,220,220,220,219    ;'HHHHH'

                db      223,223,223,223,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'
                db      32,32,32,32,219        ;'    H'

                db      219,223,223,223,219    ;'HHHHH'
                db      219,32,32,32,219       ;'H   H'
                db      219,220,220,220,219    ;'HHHHH'
                db      219,32,32,32,219       ;'H   H'
                db      219,220,220,220,219    ;'HHHHH'

                db      219,223,223,223,219    ;'HHHHH'
                db      219,32,32,32,219       ;'H   H'
                db      219,220,220,220,219    ;'HHHHH'
                db      32,32,32,32,219        ;'    H'
                db      220,220,220,220,219    ;'HHHHH'

clock_pos db 17-17,24-17,32-17,39-17,47-17,54-17
column_pos db 30,45
clock_buf       label byte  ;大时钟字元缓冲
        db        219,223,223,223,219,32,32,219,223,223,223,219,32,32,32,219,223,223,223,219,32,32,219,223,223,223,219,32,32,32,219,223,223,223,219,32,32,219,223,223,223,219 
        db        219,32,32,32,219,32,32,219,32,32,32,219,32,223,32,219,32,32,32,219,32,32,219,32,32,32,219,32,223,32,219,32,32,32,219,32,32,219,32,32,32,219 
        db        219,220,220,220,219,32,32,219,220,220,220,219,32,32,32,219,220,220,220,219,32,32,219,220,220,220,219,32,32,32,219,220,220,220,219,32,32,219,220,220,220,219 
        db        219,32,32,32,219,32,32,219,32,32,32,219,32,220,32,219,32,32,32,219,32,32,219,32,32,32,219,32,220,32,219,32,32,32,219,32,32,219,32,32,32,219 
        db        219,220,220,220,219,32,32,219,220,220,220,219,32,32,32,219,220,220,220,219,32,32,219,220,220,220,219,32,32,32,219,220,220,220,219,32,32,219,220,220,220,219 
clock_L equ ($ - offset clock_buf) / 5
        ;db        'HHHHH  HHHHH   HHHHH  HHHHH   HHHHH  HHHHH' ;输出屏幕的时钟样式，显示的H字，只是让大家看清楚大数字样式
        ;db        'H   H  H   H H H   H  H   H H H   H  H   H' ;实际输出仍是对应的扩充ASCII字元
        ;db        'HHHHH  HHHHH   HHHHH  HHHHH   HHHHH  HHHHH'
        ;db        'H   H  H   H H H   H  H   H H H   H  H   H'
        ;db        'HHHHH  HHHHH   HHHHH  HHHHH   HHHHH  HHHHH'

clock_menu label byte
db '  S:Set Time (hh:mm:ss)'
db '  A:Set Alarm   (mm:ss)'
db 'Esc:Exit to dos        '
db 20h,20h,24,25,27,26,' to move Clock   '
clock_menu_L equ ($-offset clock_menu) /4
;------------- TSR start ------------------
INT_START:      STI
                cmp     cs:work_flag,0 ;是否工作中
                jz      j10	;不是
                iret ;工作中,返回
j10:            mov     cs:work_flag,1 ;设定工作中flag
                PUSH    ES
                PUSH    SI
                PUSH    DI
                PUSH    BP
                PUSHA
                cmp     N_clock,1
                jb      j15             ;0 normal
                ja      j50             ;2 clock
                jmp     j100      ;1 not yet,leave
j15:            CMP     AX,REMOVE_AX ; Remove ? ;是否移除
                JNZ     J20 ;不是
                POPA  
                MOV     AX,CS
                MOV     BX,EXIST_FLAG ;回复已驻留标志
                MOV     CX,CS:OLD_OFF ;回传旧1ch中断offset
                MOV     DX,CS:OLD_SEG ;回传旧1ch中断segment
                JMP     J110
J20:
                CMP     AX,ASK_AX ;询问驻留
                JNZ     J50 ;不是
                POPA
                MOV     BX,EXIST_FLAG ;回复已驻留标志
                JMP     J110
                ; DO SHOW TIME
J50:            cmp     ax,Alarm_set_ask ;是否设定闹钟
                jnz     j52 ;不是
                mov     delay_count,cx ;存入闹钟计时
                dec     alarm_count ;启动3秒闹钟alarm
j52:
                cmp     delay_count,0 ;闹钟计数是否到0
                jnz     j53 ;不
                cmp     alarm_count,alarm_time  ;3秒闹钟是否已启动
                jz      j60 ;仍未启动
                jmp     short j55
.386
j53:            xor     eax,eax
                dec     delay_count ;倒数闹钟计数
                mov     ax,delay_count ;存入闹钟计数,准备印出
                jnz     j70 ;未到0
               ;       time_up
j55:			dec     alarm_count  ;倒数闹钟计数0,开始3秒alarm倒数,alarm完了没
                jnz     j59             ;normal,完了,回复正常时钟显示
                ;       reset alarm string
                cmp     N_clock,2  ;大时钟标志是否开动  
                jnz     j60
                mov     ax,0600h                 ;cls
                mov     bh,clock_color           ;attribute
                mov     cx,lost_alarm_off
                mov     dx,cx
                add     dl,7
                mov     alarm_doing,0
                int     10h
                jmp     short j60
j59:            mov     alarm_doing,1
                mov     bp,offset alarm_str ;alarm文字地址
		mov	bl,alarm_att ;闹钟颜色
                mov     ax,cs
                mov     es,ax  ;对齐cs,es,准备印出es:bp字串
                jmp     j90
j60:            mov     ax,40h ;系统段
		mov	es,ax ;存段
		mov	eax,dword ptr es:[006ch] ;6c-6d,dword,取系统计时,由凌辰开始每秒18.2次累加1.这个数即总秒数
j70:		mov	ebx,10  ;eax * 10 / 182 增加准确
		mul	ebx
		mov	ebx,182
		xor	edx,edx
		div	ebx   ;total seconds  ;得总秒数
		mov	ebx,60  
		xor	edx,edx
		div	ebx   ;ax = min / edx = seconds  ;总秒数/60 ;eax商是总分钟,edx是剩余秒数
		mov	cl,dl ;second ;保存
		xor	edx,edx
		div	ebx   ;ax = hour / edx = min ;总分钟 / 60, eax商是小时,edx是剩余分钟 
.286
		mov	di,cs
		mov	es,di
		mov	di,offset time_str ;时钟字串地址
		mov	bp,di
		add	al,0   ;加法,准备做BCD 调整
                aam  ;bcd加法调整,将al的小时数,转为BCD格式 ;XXXXX
                cmp     N_clock,2
                jnz     j75
                ;       do big clock
                mov     clock_dit,0   ;大时钟数字间隔置0
                call    print_num   ;;显示大时钟(时)
                jmp     short j80
j75:            or      ax,3030h ;转为ASCII格式
		xchg	ah,al ;交换
                stosw ;存在小时地址
		inc	di  ;跳一位
j80:            mov     al,dl  ;取分钟
		add	al,0   ;加法,准备做BCD 调整
                aam ;bcd加法调整,将al的小时数,转为BCD格式  ;XXXXX
                cmp     N_clock,2
                jnz     j82
                ;       do big clock  ;开始显示大时钟
                inc     clock_dit     ;大时钟数字间隔增量
                call    print_num     ;显示大时钟 (分)
                jmp     short j85
j82:            or      ax,3030h  ;转为ASCII格式
		xchg	ah,al  ;交换
                stosw ;存分钟地址
		inc	di 
j85:            mov     al,cl ;取秒
		add	al,0  ;和上面一样
                aam                                                     ;XXXXX
                cmp     N_clock,2
                jnz     j87
                ;       do big clock
                inc     clock_dit   ;大时钟数字间隔增量
                call    print_num  ;显示大时钟 (秒)
                call    print_screen
                mov     alarm_count,alarm_time   ;reset 重置闹钟
                jmp     short j100
j87:            or      ax,3030h
		xchg	ah,al
                stosw
                mov     alarm_count,alarm_time   ;reset 重置闹钟3秒
                mov     bl,time_att ;颜色
j90:            cmp     N_clock,2
                mov     dh,0 ;行
		mov	dl,80-8 ;列位置
                jnz     j95
                mov     dh,alarm_y
                mov     dl,alarm_x
                cmp     clock_my,box_y
                jnz     j95
                cmp     clock_mx,box1_x - clock_L - 8
                jbe     j95
                mov     dl,box_x
j95:
                mov     lost_alarm_off,dx
                mov     cx,8 ;字数
		mov	bh,0  ;显示页
		mov	ax,1300h ;印出 es:bp字串
		int	10h
J100:
                POPA
J110:           POP     BP
                POP     DI
                POP     SI
                POP     ES
                mov     cs:work_flag,0 ;重置不在工作中的标志
                cmp     N_clock,2
                jnz     j120
                ret
j120:
                IRET ;返回
;------------------------------------------------
print_num:      pusha   ;显示大时钟(时,分,秒)大数字
                mov     bp,2
                mov     cx,cs
                mov     ds,cx
                mov     es,cx
print_n10:      push    ax
                mov     al,ah
                mov     ah,0
                mov     si, num_L * 5
                mul     si
                mov     si,ax
                add     si,offset number
                mov     cx,5
                mov     bx,offset clock_pos
                add     bl,clock_dit  ;由数字间隔增量表,取得数字框线字元位置
                mov     al,[bx]
                mov     ah,0
                mov     di,offset clock_buf
                add     di,ax
print_n20:      push    di
                push    cx
                mov     cx,num_L
                rep     movsb  ;搬到暂存区
                pop     cx
                pop     di
                add     di,42
                loop    print_n20
                ;
                inc     clock_dit  ;下一个数字
                pop     ax
                mov     ah,al
                dec     bp
                jnz     print_n10
                dec     clock_dit
                ;
                popa
                ret
;------------------------------------------------
print_screen:   mov     dh,clock_My    ;显示大时钟框架
                mov     dl,clock_Mx
                mov     cx,5
                mov     si,offset clock_buf
print_n30:      push    cx
                push    dx
                mov     bh,0
                mov     ah,2
                int     10h
                mov     bp,clock_L      ;42
                mov     bl,clock_color
                call    print_color
                pop     dx
                pop     cx
                inc     dh
                loop    print_n30
                ret
;------------------------------------------------
time_str        db      '00:00:00',0   ;时钟字串
alarm_str	db	' -Alarm-',0  ;闹钟字串
tsr_end 	equ	$

NOT_EXIST       DB      'Clock not install!','$'
RELEASE_STR     DB      'Clock Removed!','$'
EXIST_STR       DB      'Clock already installed!','$'
install_str     DB      'Clock Installed',0dh,0ah
                db      'Type clock s mm:ss to set timer.',0dh,0ah
                db      'Type clock c to run normal Clock.',0dh,0ah
                db      'Type clock u to remove','$'
alarm_install   DB      'Alarm Installed',0dh,0ah,'$'
over_limit      db      'Over limit !!!',10,13,'$'
Err_Format      db      'Times format error !!!',10,13,'$'
minute          dw      0
second          dw      0
min_limit       dw      60  ;分钟限制
sec_limit       dw      60  ;秒钟限制
alarm_set       db      0   ;闹钟设定与否
ratioA          dw      10  
ratioB          dw      182 
limit_time      equ     10 ;限制闹钟时间,最少10秒

INIT:           MOV     SI,82H ;psp参数起点
                xor     cx,cx 
                mov     cl,[si-2] ;get length ;取参数长度
                jcxz    s70 ;0 表示没有参数
                MOV     AL,[SI]  ;取参数第一byte
                mov     bx,cx 
                mov     byte ptr ds:[si+bx-1],0 ;clear 0dh ;将参数最后回车置0
                and     al,11011111b ;转大写
                cmp     al,'C' ;是否大时钟参数
                jnz     s5
                call    clock_main ;大时钟子程序
                call    cls
                jmp     short s16 ;quit

s5:             CMP     AL,'U' ;是否U
                JZ      S10 ;是,表示要移除
                CMP     AL,'S' ;是否S
                JNZ     S70 ;不是
                CALL    READ_TIME ;读取s参数之后的闹钟设定 如 s 1:10 ;存入delay_count
                mov     alarm_set,0 ;清除
                jc      SHORT S70 ;若cf=1表示闹钟参数错误
                mov     alarm_set,1  ;cf=0,表示闹钟参数成功,设定alarm_set
                jmp     short s70

S10:            MOV     AX,REMOVE_AX ;询问是否驻留?
                INT     1cH  ;呼叫 
                CMP     BX,EXIST_FLAG ;若已驻留,则会传回驻留标志,是否?
                JZ      S20 ;是 
                MOV     DX,OFFSET NOT_EXIST ;未驻留而有u参数,印出未驻留字串,离开

S15:            MOV     Ah,9
                INT     21H
s16:            MOV     AH,4CH
                INT     21H

S20:            PUSH    AX  ;以下准备移除驻留的工作
                PUSH    AX
                PUSH    DS
                MOV     DS,DX ; 参看41行,这时候dx:cx是旧1c中断的原地址
                MOV     DX,CX 
                MOV     AX,251cH ;重置旧1c 中断地址
                INT     21H
                POP     DS
                POP     ES  ; GET TSR CS 取驻留中断的CS放入ES

                MOV     AX,WORD PTR ES:[002CH] ;取cs [2c]中psp地址
                MOV     ES,AX
                MOV     AH,49H ;释放psp内存
                INT     21H
                POP     ES  ;
                MOV     AH,49H ;释放中断内存
                INT     21H
                MOV     DX,OFFSET RELEASE_STR ;离开
                JMP     SHORT S15
S70:            ; Install, ask first ;以下开始做驻留/或设定闹钟工作
                MOV     AX,REMOVE_AX ;先做询问
                INT     1cH
                CMP     BX,EXIST_FLAG ;是否已驻留?
                jnz     s75 ;不是 ;去驻留
                cmp     alarm_set,1 ;是否设定闹钟
                jz      s77 ;是,去设定闹钟
                MOV     DX,OFFSET EXIST_STR  ;已驻留而又再run程式,又不是设闹钟,所以走人
                Jmp     S15
                ;       Not install
s75:
                MOV     AL,1cH  ;1c中断
                MOV     AH,35H
                INT     21H  ;读取旧1c中断
                MOV     OLD_OFF,BX ;保存
                MOV     OLD_SEG,ES
                MOV     AL,1cH 
                MOV     AH,25H
                MOV     DX,OFFSET INT_START ;我的1ch中断地址
                INT     21H ;设定新1ch中断
s77:            cmp     alarm_set,0  ;是否设定闹钟
                jz      s85  ;不是
                mov     ax,Alarm_set_ask ;设定新闹钟
                mov     cx,delay_count ;放入闹钟计数，子程序read_time已读取
                INT     1cH ;设定
                ;
                mov     dx,offset alarm_install ;　；闹钟已设字串
                jmp     short s90
s85:            MOV     DX,OFFSET install_str ;　；已驻留字串
s90:            mov     ah,9
                INT     21H
                MOV     DX,OFFSET tsr_end      ;　；驻留tsr_end之前的代码
                INT     27H
;--------------------------------------------------------------
;大时钟子程序
clock_main:     call    cls            
                call    clsc		;draw blue menu box  ;绘制大时钟屏幕
                mov     ah,2h       ;get current time  ;读取原来时间
                int     1Ah
                mov     ori_hourmin,cx ;save 存
                mov     ori_sec,dx
                mov     n_clock,2
                call    get_old_time  ;读取系统时间
                call    close_cursor
                mov     dl,clock_menu_x
                mov     dh,clock_menu_y
                mov     si,offset clock_menu
                mov     bl,clock_menu_color
                mov     cx,4    ; 4 line
clock_m10:      push    dx		;以下列印功能表 
                mov     bh,0
                mov     ah,2
                int     10h
                push    si
                push    cx
                mov     bp,clock_menu_L
                call    print_color
                pop     cx
                pop     si
                pop     dx
                inc     dh
                add     si,clock_menu_L
                loop    clock_m10
clock_m20: 	;以下测试输入,分别对S/A/ESC/上下左右做适当处理
                mov     ah,1 
                int     16h
                jnz     clock_m25 ;是否有输入?
                call    do_clock ;没有,则去处理大时钟计时
                jmp     short clock_m20
clock_m25:      mov     ah,0
                int     16h
                cmp     ah,esc_key ;ESC ?
                jnz     clock_m26
                jmp     clock_m50
clock_m26:      cmp     alarm_doing,1   ;alarm !!! don't move
                jz      clock_m20

                cmp     ah,up_key ;上
                jnz     clock_m27
                cmp     clock_my,box_y
                jbe     clock_m20
                mov     cx,word ptr clock_mx ;-----------clear border
                add     ch,4
		mov	dx,cx
		add	dl,clock_L - 1
		dec	clock_my
                jmp     short clock_m33
clock_m27:      cmp     ah,down_key  ;下
                jnz     clock_m30
                cmp     clock_my,box1_y - 8
                jae     clock_m20
                mov     cx,word ptr clock_mx ;-----------clear border
		mov	dx,cx
		add	dl,clock_L - 1
                inc     clock_my
                jmp     short clock_m33
clock_m30:      cmp     ah,Left_key  ;左
                jnz     clock_m32
                cmp     clock_mx,box_x
                jbe     clock_m20
                mov     cx,word ptr clock_mx ;-----------clear border
                add     cl,clock_L - 1
                mov     dx,cx
                add     dh,4
                dec     clock_mx
                jmp     short clock_m33
clock_m32:      cmp     ah,Right_key ;右
                jnz     clock_m34
                cmp     clock_mx,box1_x - clock_L + 1
                jae     clock_m48       ;jae     clock_m20
                mov     cx,word ptr clock_mx ;-----------clear border
                mov     dx,cx
                add     dh,4
                inc     clock_mx
clock_m33:      call    clear_clock
                jmp     clock_m20

clock_m34:      and     al,11011111b
                cmp     al,'S'  ;是否S
                jnz     clock_m40
                mov     settime_flag,1
                call    clock_set ;设定新时间
                jmp     clock_m20
clock_m40:      cmp     al,'A' ;是否A
                jnz     clock_m48
                call    clock_alarm  ;设定闹钟
clock_m48:      jmp     clock_m20
clock_m50:      cmp     settime_flag,0
                jz      clock_m60
                mov     cx,ori_hourmin
                mov     dx,ori_sec
                mov     ah,03h ;restore current time
                int     1Ah  ;存回系统时间,离开
clock_m60:      ret
;--------------------------------------------------------------
clear_clock:   ;清除框线子程序,清除因移动而残留的框线，位置由上下左右键决定并传入
                mov     ax,0600h                 ;cls
                mov     bh,clock_color           ;attribute
                int     10h
                ret
;--------------------------------------------------------------
;闗闭光熛
close_cursor:	mov     cx,3030h
                mov     ah,1
                int     10h             ;close cursor
                ret
;--------------------------------------------------------------
;设定新时间子程序
clock_set:      mov     dl,clock_menu_x + clock_menu_L + 1
                mov     dh,clock_menu_y
                mov     bh,0
                mov     ah,2
                int     10h
                mov     cx,0c0dh
                mov     bh,0
                mov     ah,1
                int     10h
                mov     al,'>'
                int     29h
clock_s20:
                call    read_time_set
                mov     ah,2dh   ;set user timer
                int     21h
                mov     cx,9
clock_s30:      call    backspace
                loop    clock_s30
                ret
;--------------------------------------------------------------
;模拟BACKSPACE
backspace:      mov dl,8
                mov ah,2
                int 21h
                mov dl,20h
                int 21h
                mov dl,8
                int 21h
                ret
;--------------------------------------------------------------
;读取时,分,秒子程序
read_time_set:
                mov cx,3
                lea di,dit_limit ; 23 and 59 limit table
                mov bp,10
                lea bx,hour
read_Alarm_set:
next2:          call check_key
                mov dl,al
                call check_char
                jc next2
                cmp al,[di]
                jb next2a
                ja next2
                mov ah,[di+2] ;get new limit
                mov [di+1],ah ;save it
next2a:
                push ax
                mov ah,2
                int 21h
                pop ax
                cbw
                mul bp ; x 10
                mov si,ax
                inc di
next2b:
                call check_key
                mov dl,al
                call check_char
                jc next2b
                cmp al,[di]
                ja next2b
                cbw
                add si,ax  ;get 2 digit
                mov ax,si
                mov [bx],al    ; save hour,min,sec
                inc bx       ;next 00
                inc di ;next limit
                inc di
                mov ah,2
                int 21h
                cmp cx,1
                jz  next3
                mov dl,':'
                mov ah,2
                int 21h
                loop next2
next3:
                mov ch,hour
                mov cl,min
                mov dh,sec
                cmp     alarm_flag,0
                jnz     next9
                ; adjust
                sub dh,13
                jns next5
                neg dh
                sub dh,60
                neg dh
next5:
                sbb cl,0
                jns next6
                neg cl
                sub cl,60
                neg cl
next6:
                sbb ch,0
next9:
                ret
;--------------------------------------------------------------
;判别数字子程序
check_char:     ; lodsb
                cmp     al,'0'
                jb      check_c10    ;not digit
                cmp     al,'9'
                ja      check_c10   ;not digit
                sub     al,'0'
                clc
                ret
check_c10:
                stc
                ret
;--------------------------------------------------------------
;设定闹钟子程序
clock_alarm:	mov     dl,clock_menu_x + clock_menu_L + 1
                mov     dh,clock_menu_y + 1
                mov     bh,0
                mov     ah,2
                int     10h
                mov     cx,0c0dh
                mov     bh,0
                mov     ah,1
                int     10h
                mov     al,'>'
                int     29h
                mov     cx,2
                lea     di,dit_limit + 3  ;min  59 limit table
                mov     bp,10
                lea     bx,min
                mov     alarm_flag,1
                call    read_Alarm_set
		pusha
                mov     cx,6
clock_a30:      call    backspace
                loop    clock_a30
		popa
                mov     ax,0
                mov     al,cl
                mov     minute,ax
                mov     al,dh
                mov     second,ax
                call    count_limit
		jc	clock_a50
                mov     ax,Alarm_set_ask ;设定新闹钟
                mov     cx,delay_count ;放入闹钟计数，子程序read_time已读取
                call    INT_START
clock_a50:
                mov     alarm_flag,0
                ret
;--------------------------------------------------------------
;读取参数,设定闹钟
read_time:   ;　　;以下读取s 之后的文字如 11:30等等，先转为总秒数，再乘18.2(1ch中断每秒运行次数)，请自行参详．．
                add     si,2 ;point to time set
                mov     di,offset minute
                mov     bx,offset min_limit
                mov     cx,2
                push    cs
                pop     es
rt10:           xor     ax,ax
                lodsb
                cmp     byte ptr [si],':'
                jz      rt15
                cmp     byte ptr [si],0
                jz      rt15
                sub     al,'0'
                mov     ah,al
                lodsb
rt15:           sub     al,'0'
                aad
                cmp     ax,[bx]
                jb      rt20
                mov     dx,offset over_limit
rt16:           mov     ah,9
                int     21h
                jmp     short readtx
rt20:           stosw
                inc     bx
                inc     bx
                dec     cx
                jz      rt50
                lodsb
                cmp     al,':'
                jz      rt10
                cmp     al,0
                jz      rt50
rt40:           mov     dx,offset Err_format
                jmp     short rt16

rt50:           call    count_limit
                jc      rt40
                ret
readtx:         stc
                ret
;------------------------------------------------------------------------------
;大时钟工作子程序
;这是利用读不到键之余，闲置时间运行的子程序，也可说无时无刻不在运行，
;这就等于int1cｈ的作用（每1/18.2一次）
;所以大时钟的操作不须常驻，只是透过呼叫int_start来模拟int1ch
do_clock:       call    time_check  ;check,是否1/18.2
                jnc     do_clockx
                call    close_cursor
                call    INT_START  ;模拟int1ch 呼叫
do_clockx:      ret
;------------------------------------------------------------------------------
count_limit:    cmp     minute,0
                jnz     cc20
                cmp     second,0
                jnz     cc20
cc10:           stc
                ret
cc20:           mov     ax,minute
                mov     bx,60
                mul     bx
                add     ax,second
                cmp     ax,limit_time
                jb      cc10
                mul     ratioB
                div     ratioA
                mov     delay_count,ax
                clc
                ret
;----------------------------------------------------------------------------------
print_color:    ;si = offset , bp = count , bl=color
		mov ah,3
		mov bh,0
		int 10h ;get cursor position
re_print:
		push dx ;save it
		lodsb
		mov ah,9
		mov bh,0
		mov cx,1
                ;mov bl,man_color
		int 10h  ;print 1 bytes with red color
		pop dx	;restore cursor position
		inc dl	; forward 1 byte
		mov bh,0
		mov ah,2 ;get new cursor position
		int 10h
		dec bp	;next bytes
		jnz re_print
		ret
;----------------------------------------------------------------------------------
check_key:      mov     ah,1
                int     16h
                jnz     check_keyx
                call    time_check
                jnc     check_key
                pusha
                mov     bh,0
                mov     ah,3
                int     10h             ;read cursor position
                push    dx
                call    close_cursor
                call    INT_START
                mov     cx,0c0dh                ;open cursor
                mov     bh,0
                mov     ah,1
                int     10h
                pop     dx
                mov     ah,2
                mov     bh,0
                int     10h             ;restore cursor position
                popa
                jmp     short check_key
check_keyx:     mov     ah,0
                int     16h
                ret
;----------------------------------------------------------------------------------
cls:		mov	ah,0fh                  ;get display mode to al
		int	10h
		mov	ah,0                    ;Set display mode
		int	10h
		ret
;------------------------------------------------------------------------------
;取用系统时间计数子程序
Time_check:     pusha
                push    es
                mov     ax,40h
                mov     es,ax
                mov     ax,es:[006ch] ;get system time count
                cmp     ax,old_time
                jz      time_checkx
                mov     old_time,ax  ;1/18.2
                call    set_ori_count
                stc
                jmp     short Time_checkxx

Time_checkx:    clc
Time_checkxx:   pop     es
                popa
                ret
;---------------------------------------------------------
get_old_time:   push    ax
                push    es
                mov     ax,40h
                mov     es,ax
.386
                mov     eax,es:[006ch] ;get system time count
		mov	clock_init,eax
                mov     old_time,ax
		pop	es
                pop     ax
                ret
;--------------------------------------------------------
;绘制颜色屏幕
clsc:           mov     ax,0600h                 ;cls
		mov	bh,back_color		;attribute
		mov	cx,0			;10
		mov	ch,0			;4;top left
		mov	dl,80			;70
		mov	dh,80			;20
                int     10h

		mov	ax,0600h		 ;cls
                mov     bh,clock_color           ;attribute
                mov     cx,box_x                ;10
                mov     ch,box_y                ;4;top left
                mov     dl,box1_x               ;70
                mov     dh,box1_y               ;20
                int     10h

                ret
;---------------------------------------------------------
set_ori_count:  push    eax
                mov     eax,clock_init
                inc     eax
                mov     clock_init,eax
                pop     eax
                ret
;--------------------------------------------------------
cseg            ends
END BEGIN